#include "tasktargettest.h"

#include <gdbio/qtRioNet.h>
#include <adapter/qtRbbSerial.h>
#include <mopenocd.h>

#include <QDateTime>

using namespace mopenocd;

static void loghandler(void *ctx, const char *fmt, ...)
{
    taskTest *t = static_cast<taskTest*>(ctx);
    QString str;
    va_list va;

    va_start(va, fmt);
    str = str.vsprintf(fmt, va);
    va_end(va);

    if (t->showtime)
    {
        QDateTime tm = tm.currentDateTime();
        QString ts = tm.toString("hh:mm:ss:zzz");

        str = ts + " " + str;
    }

    emit t->outLog(str);
}

taskTargetTest::taskTargetTest()
{
    isrun = true;
}

taskTargetTest::~taskTargetTest()
{
    isrun = false;
    wait(5000);
}

void taskTargetTest::run()
{
    qtRbbSerial ad;
    jtag_tap tap;
    targetRISCV ta;
    gdbRDP gdb;
    qtServerIO sio;
    gdbPacket pbuf;
    struct testReq q;
    int ret;
    QString comname, combd;

    loghandler(this, "Target Test Start");

    if (taskTest::params.isEmpty())
    {
        loghandler(this, "no params");
        return;
    }

    if (pbuf.bufsz() == 0)
    {
        loghandler(this, "fail init buf\n");
        return;
    }

    comname = taskTest::params.split(":").first();
    combd = taskTest::params.split(":").last();

    loghandler(this, "open serial(%s)\n", taskTest::params.toStdString().c_str());

    if (!ad.open(comname.toStdString().c_str(), combd.toUInt()))
    {
        loghandler(this, "fail open com\n");
        return;
    }

    loghandler(this, "open serial success");

    tap.bind(&ad);
    tap.init();
    tap.jtag_init_inner();

    loghandler(this, "idcode: %x", tap.idCode());

    ta.setLogger(this, loghandler);
    ta.bind(&tap);
    ta.init();

    ret = ta.examine();
    if (ret == 0)
    {
        loghandler(this, "examine success");
    }
    else
    {
        loghandler(this, "examine fail");
    }

    while (isrun)
    {
        if (!getReq(q))
        {
            msleep(50);
            continue;
        }

        taskTest::showtime = true;
        loghandler(this, "test start");

        switch (q.op) {
        case 10:
        {
            ret = ta.softReset();
            loghandler(this, "softreset-run ret(%d)", ret);
        }break;
        case 11:
        {
            ret = ta.softReset(true);
            loghandler(this, "softreset-halt ret(%d)", ret);
        }break;
        case 9:
        {
            ret = tap.reset();
            loghandler(this, "hard reset ret(%d)", ret);
        }break;
        case 7:
        {
            ret = ta.halt();
            loghandler(this, "halt ret(%d)", ret);
        }break;
        case 6:
        {
            ret = ta.resume(true, 0, 0, 0);
            loghandler(this, "run ret(%d)", ret);
        }break;
        case 5:
        {
            ret = ta.pollCurStatus();
            loghandler(this, "poll state(%d) ret(%d)",ta.state(), ret);
        }break;
        case 3:
        {
            struct reg r = {0};
            uint32_t v;
            QString str;
            int id;

            id = q.param.toInt();

            if (id > 0)
            {
                struct reg r;

                r.id = id;
                r.val64 = 0x12345678a5a5a5a5;
                ret = ta.writeReg(&r);
                loghandler(this, "ret(%d), reg(%d): %llx", ret, r.id, r.val64);
            }
        }break;
        case 8:
        case 0:
        {
            struct reg r = {0};
            int id;

            id = q.param.toInt();

            taskTest::showtime = false;

            if (id == -1)//读所有通用寄存器
            {
                int gprNums = 32;

                for (int i = 0; i < gprNums; i ++)
                {
                    r.id = i;
                    ret = ta.readReg(&r);
                    loghandler(this, "ret(%d), reg(%d): %llx", ret, r.id, r.val64);
                }
            }
            else if (id >= 0)
            {
                r.id = id;
                ret = ta.readReg(&r, (q.op == 0));
                loghandler(this, "ret(%d), reg(%d): %llx", ret, r.id, r.val64);
            }

            taskTest::showtime = true;
            loghandler(this, "end ReadReg");
        }break;
        case 4:
        {
            target_addr_t address;

            address = q.param.toULong(nullptr, 16);
            ret = ta.removeBreakpoint(address);
            loghandler(this, "delbrk(0x%llx) ret %d", address, ret);
        }break;
        case 1:
        {
            target_addr_t address;
            uint32_t length = 4;

            address = q.param.toULong(nullptr, 16);
            ret = ta.insertBreakpoint(address, length, BKPT_SOFT);
            loghandler(this, "addsoftbrk(%llx) ret %d", address, ret);
        }break;
        case 2:
        {
            target_addr_t addr;
            uint32_t size;
            QByteArray buf;
            QString str;

            str = q.param.split(":").first();
            addr = str.toULong(nullptr, 16);
            str = q.param.split(":").last();
            size = str.toUInt();

            if (addr == 0 || size == 0)
            {
                loghandler(this, "ERROR: addr or size is 0");
                break;
            }

            buf.resize(size);

            loghandler(this, "read mem<0x%llx, %d>", addr, size);

            //ret = ta.readMem(addr, 1, size, (uint8_t*)buf.data());
            //loghandler(this, "read(BYTE) mem ret(%d)", ret);

            //ret = ta.readMem(addr, 2, size/2, (uint8_t*)buf.data());
            //loghandler(this, "read(SHORT) mem ret(%d)", ret);

            ret = ta.readMem(addr, 4, size/4, (uint8_t*)buf.data());
            loghandler(this, "read(WORD) mem ret(%d)", ret);
        }break;
        default:
            break;
        }
    }

    qDebug("taskTarget exit");
}
